////////////////////////////////////////////////////////////////////////////
//
//  CryEngine Source File.
//  Copyright (C), Crytek.
// -------------------------------------------------------------------------
//  File name:   StreamEngine.h
//  Created:     27/07/2010 by Timur.
//  Description: Streaming Engine
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef _CRY_SYSTEM_STREAM_ENGINE_HDR_
#define _CRY_SYSTEM_STREAM_ENGINE_HDR_

#include "IStreamEngine.h"
#include "ISystem.h"
#include "TimeValue.h"

#include <CryThread.h>
#include "StreamIOThread.h"
#include "StreamReadStream.h"

enum EIOThread
{
	eIOThread_HDD = 0,
	eIOThread_Optical = 1,
	eIOThread_InMemory = 2,
	eIOThread_Last = 3,
};

//////////////////////////////////////////////////////////////////////////
class CStreamEngine : public IStreamEngine, public ISystemEventListener,public IInputEventListener
{
public:
	CStreamEngine();
	~CStreamEngine();


	void Shutdown();
	// This is called to cancel all pending requests, without sending callbacks.
	void CancelAll();

	//////////////////////////////////////////////////////////////////////////
	// IStreamEngine interface
	//////////////////////////////////////////////////////////////////////////
	IReadStreamPtr StartRead (const EStreamTaskType tSource, const char* szFile, IStreamCallback* pCallback, StreamReadParams* pParams = NULL);
	void BeginReadGroup();
	void EndReadGroup();

	bool IsStreamDataOnHDD() const { return m_bStreamDataOnHDD; }
	void SetStreamDataOnHDD(bool bFlag) { m_bStreamDataOnHDD = bFlag; }

	void Update();
	void UpdateAndWait(bool bAbortAll = false);
	void Update(uint32 nUpdateTypesBitmask);
	
	void GetMemoryStatistics(ICrySizer *pSizer);
	IStreamEngine::SStatistics& GetStreamingStatistics();
	void ClearStatistics();
	const char* GetStreamTaskTypeName( EStreamTaskType type );

	// Will pause or unpause streaming of specified by mask data types
	void PauseStreaming( bool bPause,uint32 nPauseTypesBitmask );
	// Pause/resumes any IO active from the streaming engine
	void PauseIO( bool bPause );

	void GetBandwidthStats(EStreamTaskType type, float * bandwidth);
	//////////////////////////////////////////////////////////////////////////

	// updates the job priority of an IO job into the IOQueue while maintaining order in the queue 
	void UpdateJobPriority(IReadStreamPtr pJobStream);

	void ReportAsyncFileRequestReadDone( CAsyncIOFileRequest_AutoPtr pFileRequest );
	void ReportAsyncFileRequestDecompressed( CAsyncIOFileRequest_AutoPtr pFileRequest );
	void ReportAsyncFileRequestComplete( CAsyncIOFileRequest_AutoPtr pFileRequest );
	void AbortJob( CReadStream* pStream );


	// Dispatches synchrnous callbacks, free temporary memory hold for callbacks.
	void MainThread_FinalizeIOJobs();
	void MainThread_FinalizeIOJobs(uint32 type);

	void ReportTempMemAlloc( uint32 nSizeAlloc,uint32 nSizeFree );
	uint32 GetCurrentTempMemorySize() const { return m_nTempAllocatedMemory; }
	void FlagTempMemOutOfBudget() { m_bTempMemOutOfBudget = true; }

	//////////////////////////////////////////////////////////////////////////
	// IInputEventListener
	//////////////////////////////////////////////////////////////////////////
	virtual bool OnInputEvent( const SInputEvent &event );
	virtual bool OnInputEventUI( const SInputEvent &event ) {	return false;	}
	//////////////////////////////////////////////////////////////////////////

	void StartFileRequest( CAsyncIOFileRequest *pFileRequest );
	void SignalToStartWork( EIOThread e, bool bForce );

protected:
	void StartThreads();
	void StopThreads();

	void ResumePausedStreams();

	// add job to current statistics
	void UpdateStatistics( CReadStream *pReadStream );
	void DrawStatistics();

	void PushRequestToAsyncCallbackThread( CAsyncIOFileRequest *pFileRequest );

	//////////////////////////////////////////////////////////////////////////
	// ISystemEventListener
	//////////////////////////////////////////////////////////////////////////
	virtual void OnSystemEvent( ESystemEvent event,UINT_PTR wparam,UINT_PTR lparam );
	//////////////////////////////////////////////////////////////////////////

protected:
	// streaming statistics
	SStatistics	m_Statistics;
	CTimeValue m_TimeOfLastReset;
	CTimeValue m_TimeOfLastUpdate;

	//////////////////////////////////////////////////////////////////////////
	CryMT::set<CReadStream_AutoPtr> m_streams;
	CryMT::vector<CReadStream_AutoPtr> m_finishedStreams;
	std::vector<CReadStream_AutoPtr> m_pausedStreams;

	// 2 IO threads.
	_smart_ptr<CStreamingIOThread> m_pThreadIO[eIOThread_Last];
	std::vector<_smart_ptr<CStreamingWorkerThread> > m_decompressThreads;
	std::vector<_smart_ptr<CStreamingWorkerThread> > m_asyncCallbackThreads;

	uint32 m_nPausedDataTypesMask;

	uint64 m_nTotalBytesUnziped;
	CTimeValue m_totalUnzipTime;

	bool m_bStreamDataOnHDD;
	bool m_bUseOpticalDriveThread;

	bool m_bTempMemOutOfBudget;

	//////////////////////////////////////////////////////////////////////////
	// Streaming statistics.
	//////////////////////////////////////////////////////////////////////////
	CryCriticalSection m_csStats;
	std::vector<CAsyncIOFileRequest_AutoPtr> m_statsRequestList;

	struct SExtensionInfo
	{
		SExtensionInfo() : m_fTotalReadTime(0.0f), m_nTotalRequests(0), m_nTotalReadSize(0),
			m_nTotalRequestSize(0)
		{
		}
		float m_fTotalReadTime;
		size_t m_nTotalRequests;
		uint64 m_nTotalReadSize;
		uint64 m_nTotalRequestSize;
	};
	typedef std::map<string, SExtensionInfo> TExtensionInfoMap;
	TExtensionInfoMap m_PerExtensionInfo;

	//////////////////////////////////////////////////////////////////////////
	// Used to calculate unzip bandwidth for statistics.
	uint32 m_nUnzipBandwidth;
	uint32 m_nUnzipBandwidthAverage;
	uint64 m_nTempBytesUnziped;
	CTimeValue m_tempUnzipTime;
	CTimeValue m_nLastBandwidthUpdateTime;
	
	bool m_bStreamingStatsPaused;
	bool m_bInputCallback;
	bool m_bShutDown;	
	//////////////////////////////////////////////////////////////////////////

	volatile int m_nBatchMode;

	// Memory currently allocated by streaming engine for temporary storage.
	volatile int m_nTempAllocatedMemory;
};

#endif